﻿namespace WayneGameSolution.Communicate
{
    using System;
    using System.Runtime.InteropServices;
    using System.Runtime.Serialization ;
    using System.Runtime.Serialization.Formatters  ;
    using System.Runtime.Serialization.Formatters.Soap   ;
    using System.Runtime.Serialization.Formatters.Binary    ;
    using WayneGameSolution.Packs;
    using WayneGameSolution.Strategies;
    using System.Collections.Generic.Sync;
    using System.Collections.Generic;
    using System.Linq;
    public abstract class Codec : ICodec
    {
        [Obsolete("This soap codec uses refelection a lot.")]
        public static Codec SoapFormatter = new FormatterCodec<SoapFormatter>();

        [Obsolete("This soap codec uses refelection a lot.")]
        public static Codec BinaryFormatter = new FormatterCodec <BinaryFormatter> ();
        public static Codec NetDataContract = new FormatterCodec<NetDataContractSerializer>();
        public static Codec JsonDataContract = new JsonCodec();
        protected static SyncDictionary<Type, IEnumerable<Type>> KnownTypeDic = new SyncDictionary<Type, IEnumerable<Type>>();


       // public static Codec BinaryFormatterSlim = new FormatterCodecSlim<BinaryFormatter>();
        public static SyncDictionary<int, Type> RegistedPackTypes;
        public static Codec GetCodec(string name_space)
        {
            return (Codec)Unity.DefaultContainer.Resolve<ICodec>(name_space);
        }

        public abstract byte[] ToBytes(ICrypt Crypt ,IDataPack workingPack);
        public abstract IDataPack ToDataPack(ICrypt Crypt ,byte[] linkPack,int flag,int tempId);

        
    }


    
    public class FormatterCodec<T> : Codec where T:System.Runtime.Serialization.IFormatter,new ()  
    {
         public override byte[] ToBytes(ICrypt Crypt, IDataPack workingPack)
        {
            T sp = new  T ();
            var stm = new System.IO.MemoryStream();
            sp.Serialize(stm, workingPack);
            return stm.ToArray();

        }

            public override IDataPack ToDataPack(ICrypt Crypt, byte[] linkPack, int flag, int tempId)
        {

            T sp = new T(); 
            var stm = new System.IO.MemoryStream(linkPack);
            var rval = (IDataPack)sp.Deserialize(stm);
            return rval;
        }
    }


    public class JsonCodec : Codec  
    {
        public JsonCodec()
        { 
        
        
        }


        public override byte[] ToBytes(ICrypt Crypt, IDataPack workingPack)
        {
            var t=workingPack.GetType();
            IEnumerable<Type >kt;
            if (!Codec.KnownTypeDic.TryGetValue (t,out kt ))
            {
                kt= Attribute.GetCustomAttributes(t,typeof(KnownTypeAttribute))
                    .Select(x => (x as KnownTypeAttribute).Type).ToArray ();
            
            }

            var sp =
                new System.Runtime.Serialization.Json.DataContractJsonSerializer
                    (workingPack.GetType(),kt);
            
            var stm = new System.IO.MemoryStream();
            sp.WriteObject(stm, workingPack);
            return stm.ToArray();

        }

        public override IDataPack ToDataPack(ICrypt Crypt, byte[] linkPack, int flag, int tempId)
        {
            var t=DataPack.PackFlagNameDictionary [flag];
            IEnumerable<Type >kt;
            if (!Codec.KnownTypeDic.TryGetValue (t,out kt ))
            {
                kt= Attribute.GetCustomAttributes(t,typeof(KnownTypeAttribute))
                    .Select(x => (x as KnownTypeAttribute).Type).ToArray ();
            
            }

            var sp = new System.Runtime.Serialization.Json.DataContractJsonSerializer(t, kt);
            var stm = new System.IO.MemoryStream(linkPack);
            var rval = (IDataPack)sp.ReadObject (stm);
            return rval;
        }
    }

    //public class FormatterCodecSlim<T> : Codec where T : System.Runtime.Serialization.IFormatter, new() 
    //{
    //    [Serializable ]
    //   public  struct proxyPack:ISerializable  
    //    {
    //       public IDataPack  P;
    //       public SerializationInfo _info;
    //       public StreamingContext _context;
    //        public proxyPack(SerializationInfo info, StreamingContext context)
    //        {
    //            P = null;
    //            _info = info;
    //            _context = context;
    //        }

    //        public void GetObjectData(SerializationInfo info, StreamingContext context)
    //        {
    //            P.GetObjectData(info, context);
    //        }


    //    }
     
    //     public override byte[] ToBytes(ICrypt Crypt, IDataPack workingPack)
    //    {
    //        proxyPack tp = new proxyPack();
    //        tp.P = workingPack;
    //        T sp = new T();
    //        var stm = new System.IO.MemoryStream();
    //        sp.Serialize(stm, tp );
    //        return stm.ToArray();

    //    }
    //     public override IDataPack ToDataPack(ICrypt Crypt, byte[] linkPack, int flag, int tempId)
    //    {
             
    //        var sp = new T();
    //        var stm = new System.IO.MemoryStream(linkPack);
    //        var rval = (proxyPack)sp.Deserialize(stm);
    //        return rval.P ;
    //    }
    //}

    


}

